# -*- coding: utf-8 -*-
import traceback
from time import sleep
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from common import log
from selenium.webdriver.support.wait import WebDriverWait


class Page:
    driver = None
    logger = log.logger

    # 构造方法，用来接收selenium的driver对象
    @classmethod
    def __init__(cls, driver):
        cls.driver = driver

    # 输入地址
    @classmethod
    def get(cls, url):
        cls.driver.get(url)

    # 关闭浏览器驱动
    @classmethod
    def quit(cls):
        cls.driver.quit()

    # 删除cookies退出账号再刷新界面
    @classmethod
    def page_logout(cls):
        cls.driver.delete_all_cookies()
        cls.driver.refresh()

    # 返回上一页
    @classmethod
    def back_page(cls):
        cls.driver.back()

    # 刷新页面
    @classmethod
    def page_refresh(cls):
        cls.driver.refresh()

    # 获取界面标题
    @classmethod
    def page_title(cls):
        page_title = cls.driver.title
        return page_title

    # 获取当前url
    @classmethod
    def page_url(cls):
        page_url = cls.driver.current_url
        return page_url

    # element对象
    @classmethod
    def element(cls, module, page, element):
        """
        :param module:
        :param page:
        :param element:
        :return:
        """
        try:
            if cls.page_is_loading():
                el = WebDriverWait(cls.driver, 10).until(EC.presence_of_element_located(module[page][element]))
                return el
        except:
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info(f'查找元素：{element}--fail', extra=m)
            return None

    # elements对象
    @classmethod
    def elements(cls, module, page, element):
        try:
            if cls.page_is_loading():
                els = WebDriverWait(cls.driver, 10).until(EC.presence_of_all_elements_located(module[page][element]))
                return els
        except:
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info(f'查找元素：{element}--fail', extra=m)
            return None

    @classmethod
    def el_xpath(cls, msg, time=10):
        try:
            if cls.page_is_loading():
                el = WebDriverWait(cls.driver, time).until(lambda driver: driver.find_element_by_xpath(msg))
                return el
        except:
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info(f'查找元素：{msg}--fail', extra=m)
            return None

    @classmethod
    def els_xpath(cls, msg, time=10):
        try:
            if cls.page_is_loading():
                els = WebDriverWait(cls.driver, time).until(lambda driver: driver.find_elements_by_xpath(msg))
                return els
        except:
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info(f'查找元素：{msg}--fail', extra=m)
            return None

    # 判断页面元素是否可见，默认等待10秒（通用方法）
    @classmethod
    def element_is_exist(cls, module, page, element):
        """
        当我们需要找到元素，并且判断该元素是否不可见时用invisibility_of_element_located或者invisibility_of_element
        """
        try:
            WebDriverWait(cls.driver, 10).until_not(EC.invisibility_of_element(module[page][element]))
            return True
        except:
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info('页面存在元素：' + element, extra=m)
            return False

    # 判断页面是否在加载中，默认等待10秒
    @classmethod
    def page_is_loading(cls):
        try:
            WebDriverWait(cls.driver, 10).until(EC.invisibility_of_element((By.XPATH, '//*[contains(text(),"加载中")]')))
            return True
        except:
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info('页面加载超时。', extra=m)
            return False

    # 判断页面是是否加载完成(网厅专用,flag1命令目前仅网厅支持)
    @classmethod
    def check_page_loading(cls, times):
        """
        :param times:等待次数，10秒/次
        :return: 超时报错信息
        """
        flag1 = True
        flag2 = True
        i = 0
        while i < times:
            sleep(0.5)
            flag1 = cls.driver.execute_script("return window.testvueTop.isLoading")
            el_list = cls.els_xpath("//div[contains(@class, 'weui-loading_toast')]")
            result = []
            for el in el_list:
                result.append('display: none;' in el.get_attribute('style'))
            flag2 = all(result)
            if (not flag1) and flag2:
                break
            i = i + 1
        try:
            flag1 or flag2
        except:
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info('页面加载超时。', extra=m)

    # sendKey方法
    @classmethod
    def send_key(cls, module, page, element, msg, is_els=False, num=None, log_info=None):
        i = 0
        s = traceback.extract_stack()
        m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
        while i < 3:
            if not is_els:
                el = cls.element(module, page, element)
            if is_els:
                el = cls.elements(module, page, element)[num]
            i = i + 1
            try:
                el.clear()
                el.send_keys(msg)
                cls.logger.info(f'输入成功--{element}:{msg}', extra=m)
                if log_info:
                    cls.logger.info(f'{log_info}', extra=m)
                break
            except Exception as e:
                cls.logger.info(f'{element}：第{i}次输入失败,错误原因：{e}', extra=m)

    # click方法
    @classmethod
    def click(cls, module, page, element, is_els=False, num=None, log_info=None):
        """
        :param log_info: 日志信息
        :param module:
        :param page:
        :param element:
        :param is_els: 判断是否是元素list
        :param num: 元素list下标
        :return:
        """
        i = 0
        el = None
        while i < 3:
            if not is_els:
                el = cls.element(module, page, element)
            if is_els:
                el = cls.elements(module, page, element)[num]
            try:
                i = i + 1
                Page.page_is_loading()
                el.click()
                if log_info:
                    s = traceback.extract_stack()
                    m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
                    cls.logger.info(f'{log_info}', extra=m)
                    # 当页面跳转比js执行快时，给element加样式则会失败
                try:
                    cls.driver.execute_script("arguments[0].setAttribute('style', arguments[1]);", el,
                                              "background: #1AFD9C; border:2px solid red;")
                except:
                    pass
                break
            except Exception as e:
                sleep(0.1)
                s = traceback.extract_stack()
                m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
                cls.logger.info(f'{element}:第{i}次点击失败,错误原因：{e}', extra=m)

    @classmethod
    def updata_style(cls, module, page, element, style="display:;"):
        '''
        临时解决开户，身份证输入框无法清除输入框添加的方法
        '''
        el = Page.element(module, page, element)
        try:
            cls.driver.execute_script("arguments[0].setAttribute('style', arguments[1]);", el,
                                      f'{style}')
        except Exception as e:
            sleep(0.1)
            s = traceback.extract_stack()
            m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
            cls.logger.info(f'{element}:修改元素样式失败：{e}', extra=m)

    # 滑动至元素可见
    @classmethod
    def swipe_to_ele(cls, module, page, element, is_els=False, num=None):
        if not is_els:
            ele = cls.element(module, page, element)
            cls.driver.execute_script("arguments[0].scrollIntoView();", ele)
        if is_els:
            ele = cls.elements(module, page, element)[num]
            cls.driver.execute_script("arguments[0].scrollIntoView();", ele)

    # 判断是否有dialog弹窗
    @classmethod
    def check_dialog(cls):
        result = cls.driver.execute_script('return document.activeElement.innerText')
        return result.find("提示") >= 0 and result.find("确定") >= 0

    # page down按键
    @classmethod
    def page_down(cls):
        js = 'window.scroll(0,document.body.scrollHeight)'
        cls.driver.execute_script(js)
        # win32api.keybd_event(8, 0, 0, 0)
        # win32api.keybd_event(8, 0, win32con.KEYEVENTF_KEYUP, 0)

    # div内的滚动条
    @classmethod
    def div_bottom(cls, msg):
        js = 'document.getElementById("%s").scrollTop=5000000000' % msg
        cls.driver.execute_script(js)

    # 滚动到浏览器顶部
    @classmethod
    def js_top(cls):
        js_top = "var q=document.documentElement.scrollTop=0"
        cls.driver.execute_script(js_top)

    # 滚动到浏览器底部
    @classmethod
    def js_bottom(cls):
        js_bottom = "var q=document.documentElement.scrollTop=1000000"
        cls.driver.execute_script(js_bottom)

    @classmethod
    def js_click(cls, module, page, element):
        ele = cls.element(module, page, element)
        cls.driver.execute_script("arguments[0].click();", ele)

    # 下拉控件输入
    @classmethod
    def select_list(cls, encode, valve):
        js = "window.testvue." + encode + "='" + valve + "'"
        s = traceback.extract_stack()
        m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
        cls.logger.info(f'{js}', extra=m)
        sleep(1)
        cls.driver.execute_script(js)
        # 下拉控件输入

    @classmethod
    def select_location(cls, encode, valve):
        js = "window.testvue." + encode + ".push('" + valve + "')"
        sleep(1)
        cls.driver.execute_script(js)

    # 下拉控件清空
    @classmethod
    def clear_select(cls, encode):
        shift = "window.testvue." + encode + ".shift()"
        sleep(1)
        cls.driver.execute_script(shift)

    # 输入框清空
    @classmethod
    def clear_edit(cls, encode):
        shift = "window.testvue." + encode + "=''"
        sleep(1)
        cls.driver.execute_script(shift)


    @classmethod
    def el_js_click(cls, ele):
        cls.driver.execute_script("arguments[0].click();", ele)

    # # 切换至弹窗
    # @classmethod
    # def switch_alert(cls):
    #     WebDriverWait(cls.driver, 10).until(EC.alert_is_present())
    #     a = cls.driver.switch_to.alert()
    #     a.accept()
    #     s = traceback.extract_stack()
    #     m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
    #     cls.logger.info('切换至弹窗OK', extra=m)

    # # 操作滑动控件
    # @classmethod
    # def control(cls, module, page, element, x=0, y=100):
    #     action_chains = ActionChains(cls.driver)
    #     el = cls.element(module, page, element)
    #     action_chains.click_and_hold(el).perform()
    #     action_chains.move_to_element_with_offset(el, x, y).perform()  # 滑动距离x横坐标，y纵坐标
    #     action_chains.release()

    # # 滑动至页面底部（end按键）
    # @classmethod
    # def swipe_down(cls):
    #     win32api.keybd_event(35, 0, 0, 0)
    #     win32api.keybd_event(35, 0, win32con.KEYEVENTF_KEYUP, 0)

    # @classmethod
    # def switch_windows(cls, title):
    #     handles = cls.driver.window_handles
    #     try:
    #         for handle in handles:
    #             if handle != cls.driver.current_window_handle:
    #                 cls.driver.switch_to.window(handle)
    #                 if title in cls.driver.title:
    #                     break
    #                 break
    #             break
    #     except Exception as e:
    #         s = traceback.extract_stack()
    #         m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
    #         cls.logger.info(f'{e}', extra=m)

    # # iframe对象
    # @classmethod
    # def switch_iframe(cls, module, page, iframe):
    #     """
    #     :param module:
    #     :param page:
    #     :param iframe:
    #     :return:
    #     """
    #     # 加入隐性等待
    #     # 此处便可以传入定位参数
    #     iframe = WebDriverWait(cls.driver, 10).until(EC.frame_to_be_available_and_switch_to_it(module[page][iframe]))
    #     # 加入日志
    #     s = traceback.extract_stack()
    #     m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
    #     cls.logger.info('切换iframe' + iframe + 'OK', extra=m)
    #     return iframe

    # # 切回主页面
    # @classmethod
    # def switch_defaultframe(cls):
    #     cls.driver.switch_to.default_content()
    #     # 加入日志
    #     s = traceback.extract_stack()
    #     m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
    #     cls.logger.info('切回主页面OK', extra=m)

    # # 判断元素是否可点击
    # @classmethod
    # def click_enable(cls, module, page, element):
    #     el = cls.element(module, page, element)
    #     return el.is_enabled()

    # # 判断element是否消失
    # @classmethod
    # def element_is_display(cls, module, page, element):
    #     """
    #     当我们需要找到元素，无需判断该元素是否可见，只判断元素是否存在在页面中时用presence_of_element_located
    #     :param module:
    #     :param page:
    #     :param element:
    #     :return:
    #     """
    #     # 加入隐性等待
    #     # 此处便可以传入定位参数
    #     el = WebDriverWait(cls.driver, 10).until_not(EC.presence_of_element_located(module[page][element]))
    #     # 加入日志
    #     s = traceback.extract_stack()
    #     m = {'appname': s[-2].filename.split('\\')[-1] + f' line in {s[-2].lineno}'}
    #     cls.logger.info('页面元素' + element + '消失', extra=m)
    #     return el


if __name__ == "__main__":
    pass
